import type { INodeTypeDescription } from 'n8n-workflow';

import type { ProgrammaticEvaluationInput, ProgrammaticViolation } from '@/validation/types';

import {
	evaluateConnections,
	evaluateNodes,
	evaluateTools,
	evaluateAgentPrompt,
	evaluateFromAi,
	evaluateTrigger,
} from './evaluators';
import {
	evaluateWorkflowSimilarity,
	evaluateWorkflowSimilarityMultiple,
} from './evaluators/workflow-similarity';
import { calculateOverallScore } from '../utils/score';

export async function programmaticEvaluation(
	input: ProgrammaticEvaluationInput,
	nodeTypes: INodeTypeDescription[],
) {
	const { generatedWorkflow, referenceWorkflow, referenceWorkflows } = input;

	const connectionsEvaluationResult = evaluateConnections(generatedWorkflow, nodeTypes);
	const nodesEvaluationResult = evaluateNodes(generatedWorkflow, nodeTypes);
	const triggerEvaluationResult = evaluateTrigger(generatedWorkflow, nodeTypes);
	const agentPromptEvaluationResult = evaluateAgentPrompt(generatedWorkflow);
	const toolsEvaluationResult = evaluateTools(generatedWorkflow, nodeTypes);
	const fromAiEvaluationResult = evaluateFromAi(generatedWorkflow, nodeTypes);

	// Workflow similarity evaluation (supports both single and multiple reference workflows)
	let similarityEvaluationResult = null;

	// Prioritize referenceWorkflows (multiple) over referenceWorkflow (single)
	if (referenceWorkflows && referenceWorkflows.length > 0) {
		try {
			similarityEvaluationResult = await evaluateWorkflowSimilarityMultiple(
				generatedWorkflow,
				referenceWorkflows,
			);
		} catch (error) {
			console.warn('Multiple workflow similarity evaluation failed:', error);
			// Fallback to neutral result if similarity check fails
			const violation: ProgrammaticViolation = {
				name: 'workflow-similarity-evaluation-failed',
				type: 'critical',
				description: `Similarity evaluation failed: ${(error as Error).message}`,
				pointsDeducted: 0,
			};
			similarityEvaluationResult = {
				violations: [violation],
				score: 0,
			};
		}
	} else if (referenceWorkflow) {
		try {
			similarityEvaluationResult = await evaluateWorkflowSimilarity(
				generatedWorkflow,
				referenceWorkflow,
			);
		} catch (error) {
			console.warn('Workflow similarity evaluation failed:', error);
			// Fallback to neutral result if similarity check fails
			const violation: ProgrammaticViolation = {
				name: 'workflow-similarity-evaluation-failed',
				type: 'critical',
				description: `Similarity evaluation failed: ${(error as Error).message}`,
				pointsDeducted: 0,
			};
			similarityEvaluationResult = {
				violations: [violation],
				score: 0,
			};
		}
	}

	const overallScore = calculateOverallScore({
		connections: connectionsEvaluationResult,
		nodes: nodesEvaluationResult,
		trigger: triggerEvaluationResult,
		agentPrompt: agentPromptEvaluationResult,
		tools: toolsEvaluationResult,
		fromAi: fromAiEvaluationResult,
		similarity: similarityEvaluationResult,
	});

	return {
		overallScore,
		connections: connectionsEvaluationResult,
		nodes: nodesEvaluationResult,
		trigger: triggerEvaluationResult,
		agentPrompt: agentPromptEvaluationResult,
		tools: toolsEvaluationResult,
		fromAi: fromAiEvaluationResult,
		similarity: similarityEvaluationResult,
	};
}
